package common

import (
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
	"github.com/inconshreveable/go-update"
)

func LookPath() (argv0 string, err error) {
	argv0, err = exec.LookPath(os.Args[0])
	if nil != err {
		return
	}
	if _, err = os.Stat(argv0); nil != err {
		return
	}
	return
}

func GetMd5(path string) (ret string, err error) {
	file, err := os.Open(path)
	defer file.Close()
	if err == nil {
		md5h := md5.New()
		io.Copy(md5h, file)
		ret = fmt.Sprintf("%x", md5h.Sum([]byte("")))
	}
	return
}

func GetstringMd5(s string) (ret string, err error) {
	md5h := md5.New()
	md5h.Write([]byte(s))
	ret = fmt.Sprintf("%x", md5h.Sum([]byte("")))
	return
}

func getAddrByDefault() (string, error) {
	conn, err := net.Dial("udp", "132.121.97.254:80")
	if err != nil {
		fmt.Println(err.Error())
		return "", err
	}
	defer conn.Close()
	return strings.Split(conn.LocalAddr().String(), ":")[0], nil
}

func GetAddr(addr string) (r string, err error) {
	resp, err := http.Get(addr)
    defer resp.Body.Close()
	if err == nil {
		body, err1 := ioutil.ReadAll(resp.Body)
		if err1 == nil {
			r = string(body)
			err = err1
			return
		}
	}
	r, err = getAddrByDefault()
	if err != nil {
		r = "127.0.0.1"
		err = nil
	}
	return
}

func WritePidFile(path string) {
	if pid := syscall.Getpid(); pid != 1 {
		ioutil.WriteFile(path, []byte(strconv.Itoa(pid)), 0644)
	}
}

func Update(url, targetFile string, mode os.FileMode) error {
	if mode == 0 {
		info, err := os.Stat(targetFile)
		if err != nil {
			return err
		}
		mode = info.Mode()
	}
	resp, err := http.Get(url)
    defer resp.Body.Close()
	if resp.StatusCode != 200 {
		err = fmt.Errorf("HTTPErrorcode:%d", resp.StatusCode)
	}
	if err != nil {
		return err
	}
	if err = update.Apply(resp.Body, update.Options{TargetPath: targetFile, TargetMode: mode}); err != nil {
		return err
	}
	return nil
}

func GetDelta(url string) (int64, error) {
	s, err := HttpGetter(url, nil)
	if err != nil {
		return int64(0), err
	}
	NetTime, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return int64(0), err
	}
	LocalTime := float64(time.Now().Unix())
	delta := NetTime - LocalTime
	r := fmt.Sprintf("%.0f", delta)
	return strconv.ParseInt(r, 0, 64)
}

func GetTime(delta int64) int64 {
	return time.Now().Unix() + delta
}

func Encode_base64(s string) string {
	sEn := base64.StdEncoding.EncodeToString([]byte(s))
	return sEn
}

func Decode_base64(s string) (string, error) {
	sDec, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		return "", err
	}
	return string(sDec), nil
}

func ExtractMetricAddr(s string) (string, error) {
	strs := strings.Split(s, ".")
	if len(strs) > 1 {
		if len(strings.Split(strs[1], "_")) == 4 {
			return strings.Replace(strs[1], "_", ".", -1), nil
		}
	}
	return "", fmt.Errorf("metric error")
}
